package com.example.fileprovider;

import android.os.Environment;
import android.util.SparseArray;

import java.io.File;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 自定义日志 有开关， 并且可以输入到sd卡中
 * 
 * @author llbt_wzq
 * 
 */
public class LogMgr {
    private static String TAG = "AppLog";

    /** 日志总开关 */
    private static boolean ENABLE_LOG_OUTPUT = true;

    /** 日志分开关:使能输出到SD卡 */
    private static boolean ENABLE_WRITE_TO_SD = false;

    /** 日志分段长度 */
    private static final int LOG_MAX_LEN = 3000;

    /** 每条日志的时间:日志输出日期格式 */
    private static final SimpleDateFormat LOG_DATE_FORMAT = new SimpleDateFormat("HH:mm:ss");

    /** SD卡日志输入路径 */
    private static final String LOG_DIR_IN_SD = Environment.getExternalStorageDirectory().getPath() + "/appLog";

    /** 关闭日志输出 */
    public static void closeLog() {
        if (outFile != null)
            outFile.close();
    }

    public static void v(String msg) {
        if (ENABLE_LOG_OUTPUT) {
            showLog(msg, LOGV);
        }
    }

    public static void d(String msg) {
        if (ENABLE_LOG_OUTPUT) {
            showLog(msg, LOGD);
        }
    }

    public static void i(String msg) {
        if (ENABLE_LOG_OUTPUT) {
            showLog(msg, LOGI);
        }
    }

    public static void w(String msg) {
        if (ENABLE_LOG_OUTPUT) {
            showLog(msg, LOGW);
        }
    }

    public static void e(String msg) {
        if (!ENABLE_LOG_OUTPUT)
            return;

        showLog(msg, LOGE);

        // 打印出错地点
        String errorPoint = "error at " + Thread.currentThread().getStackTrace()[2].getMethodName() + //
                " class:" + Thread.currentThread().getStackTrace()[3].getClassName() + //
                "::" + Thread.currentThread().getStackTrace()[3].getMethodName();

        android.util.Log.e(TAG, errorPoint);
        write2Sd(errorPoint, LOGE);
    }

    /***
     * 根据等级，打印日志，保持日志
     * 
     * @param msg
     * @param level
     */
    private static void showLog(String msg, int level) {
        // 过长msg的处理
        while (msg.length() >= LOG_MAX_LEN) {
            // 首先打印前LOG_LENGTH个字符
            String str1 = msg.substring(0, LOG_MAX_LEN);
            showLogShort(str1, level);
            msg = msg.substring(LOG_MAX_LEN);
        }

        if (msg.length() != 0) {
            showLogShort(msg, level);
        }
    }

    private static void showLogShort(String str, int level) {
        switch (level) {
        case LOGV:
            android.util.Log.v(TAG, str);
            break;
        case LOGD:
            android.util.Log.d(TAG, str);
            break;
        case LOGI:
            android.util.Log.i(TAG, str);
            break;
        case LOGW:
            android.util.Log.w(TAG, str);
            break;
        case LOGE:
            android.util.Log.e(TAG, str);
            break;
        }
        // 写到sd卡中
        if (level >= saveLevel) {
            write2Sd(str, level);
        }
    }

    /**
     * 在方法内部调用，打印调用信息
     */
    public static void whoInvokeMe() {
        if (!ENABLE_LOG_OUTPUT)
            return;

        String callerInfo = Thread.currentThread().getStackTrace()[3].getMethodName() + //
                " called by " + Thread.currentThread().getStackTrace()[4].getClassName() + //
                "::" + Thread.currentThread().getStackTrace()[4].getMethodName();

        d(callerInfo);
    }

    /**
     * 打印流程 静态方法中调用会不准,默认d等级
     * 
     * @param msg string-msg,可以为null
     */
    public static void printProcess(String msg) {
        if (!ENABLE_LOG_OUTPUT)
            return;

        String info = Thread.currentThread().getStackTrace()[3].getClassName() + //
                "::" + Thread.currentThread().getStackTrace()[3].getMethodName();
        if (msg != null) {
            info += "  " + msg;
        }
        showLog(info, LOGD);
    }

    /**
     * 打印流程 静态方法中调用会不准
     * 
     * @param level 0~4 代表v/d/i/w/e
     * @param msg string-msg
     */
    public static void printProcess(int level, String msg) {
        if (!ENABLE_LOG_OUTPUT)
            return;

        String info = Thread.currentThread().getStackTrace()[3].getClassName() + //
                "::" + Thread.currentThread().getStackTrace()[3].getMethodName();
        if (msg != null)
            info += "  " + msg;

        showLog(info, level);
    }

    /**
     * 初始化:创建文件
     */
    private static void init() {
        isInit = true;
        if (!ENABLE_WRITE_TO_SD) // isWrite2Sd=true才继续
            return;

        // sd是否卡存在
        if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
            return;

        // sd卡是否可写
        if (!Environment.getExternalStorageDirectory().canWrite())
            return;

        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
            String date = sdf.format(new Date());

            // create the log file 文件名
            File logFile = new File(LOG_DIR_IN_SD + "/log_" + date + ".log");
            logFile.getParentFile().mkdirs();
            if (logFile.exists())
                logFile.delete();
            logFile.createNewFile();

            // writer
            FileWriter fwriter = new FileWriter(logFile);
            outFile = new PrintWriter(fwriter);

            // write the init text
            outFile.write("----- Initiating LogToSD Session -----");
        } catch (Exception e) {
            LogMgr.e("写入日志时:发生错误" + e.toString());
        }

    }

    private static SparseArray<String> lvlMap = new SparseArray<String>();
    static {
        lvlMap.put(0, "v");
        lvlMap.put(1, "d");
        lvlMap.put(2, "i");
        lvlMap.put(3, "w");
        lvlMap.put(4, "e");
    }

    /**
     * 向文件中写日志
     * 
     * @param msg
     * @param level v/d/i/w/e
     */
    private static void write2Sd(String msg, int level) {
        if (isInit == false)
            init();
        if (null == outFile)
            return;

        Date rightNow = new Date();
        String time = LOG_DATE_FORMAT.format(rightNow);

        String type = lvlMap.get(level);
        type = (type == null) ? "i" : type;

        outFile.write(time + TAB_SPACE + type + "/" + TAG + ":" + msg + "\n");
        outFile.flush();
    }

    /** 保存的日志等级 */
    public static final int LOGV = 0;
    public static final int LOGD = 1;
    public static final int LOGI = 2;
    public static final int LOGW = 3;
    public static final int LOGE = 4;
    public static final int saveLevel = LOGV;// 大于等于 saveLevel的日志被保存到sd卡

    private static PrintWriter outFile = null;// 保存一个静态的writer,注意在App退出的时候，关闭PrintWriter
    private static final String TAB_SPACE = "    ";// 4个空格代替tab
    private static boolean isInit = false;

    // public static enum LogLevel {
//        //@formatter:off 
//         V(0,"v"), 
//         D(1,"d"), 
//         I(2,"i"), 
//         W(3,"w"), 
//         E(4,"e");
//         //@formatter:on
    //
    // private int iValue;
    // private String strValue;
    //
    // private LogLevel(int i, String s) {
    // iValue = i;
    // strValue = s;
    // }
    //
    // public String getString(int i) {
    // for (LogLevel lvl : LogLevel.values()) {
    // if (lvl.iValue == i) {
    // return lvl.strValue;
    // }
    // }
    // return null;
    // }
    // }
}
